package pvp

import (
	"context"
	"errors"
	"log"
	"match-server/pvp/dto"
	"match-server/pvp/service"
	"sync"
	"time"
)

// 定义错误常量，提高代码可维护性
var (
	ErrMatchTypeNotExist = errors.New("匹配类型不存在")
	ErrAlreadyInQueue    = errors.New("已在匹配队列中")
	ErrJoinFailed        = errors.New("加入匹配失败，请稍后再试")
)

// GlobalMatchMgr 全局匹配管理器实例
var GlobalMatchMgr = newMatchServiceMgr()

func InitMatchService(ctx context.Context) {
	GlobalMatchMgr.AddMatchService(DEFAULT_TYPE, service.NewDefaultMatchService())
	GlobalMatchMgr.AddMatchService(CROSS_PVP, service.NewPvpMatchService())

	// 启动
	for _, matchService := range GlobalMatchMgr.services {
		err := matchService.Start(ctx)
		if err != nil {
			log.Printf("启动失败，请检查。")
			return
		}
	}
}

// MatchServiceMgr 匹配器管理器
type MatchServiceMgr struct {
	services       map[int]service.MatchService
	lock           sync.RWMutex
	ctx            context.Context
	cancel         context.CancelFunc
	wg             sync.WaitGroup   // 用于等待所有goroutine完成
	activeMatchers map[int]struct{} // 跟踪当前在匹配队列中的玩家ID
	matcherLock    sync.RWMutex     // 用于保护activeMatchers的锁
}

// NewMatchServiceMgr 创建匹配服务管理器
func newMatchServiceMgr() *MatchServiceMgr {
	ctx, cancel := context.WithCancel(context.Background())
	m := &MatchServiceMgr{
		services:       make(map[int]service.MatchService),
		ctx:            ctx,
		cancel:         cancel,
		activeMatchers: make(map[int]struct{}),
	}

	return m
}

// AddMatchService 添加一个匹配器
func (mgr *MatchServiceMgr) AddMatchService(matchType int, s service.MatchService) {
	mgr.lock.Lock()
	defer mgr.lock.Unlock()

	if _, exists := mgr.services[matchType]; exists {
		log.Printf("警告： 处理器类型Type = %d 存在重复", matchType)
	}

	mgr.services[matchType] = s
	log.Printf("匹配器Type = %d 已注册", matchType)
}

// AddMatcher 加入匹配
func (mgr *MatchServiceMgr) AddMatcher(matchType int, matcher dto.Matcher) (<-chan dto.MatchResult, error) {
	// 检查玩家是否已经在匹配中
	matcherId := matcher.GetMatcherId()

	mgr.matcherLock.RLock()
	_, exists := mgr.activeMatchers[matcherId]
	mgr.matcherLock.RUnlock()

	if exists {
		return nil, ErrAlreadyInQueue
	}

	// 先读锁获取服务，避免长时间持有写锁
	mgr.lock.RLock()
	matchService, serviceExists := mgr.services[matchType]
	mgr.lock.RUnlock()

	if !serviceExists {
		return nil, ErrMatchTypeNotExist
	}

	// 创建上下文，允许超时和取消
	matcherCtx, matcherCancel := context.WithTimeout(mgr.ctx, 30*time.Second)

	// 标记玩家为匹配中
	mgr.matcherLock.Lock()
	mgr.activeMatchers[matcherId] = struct{}{}
	mgr.matcherLock.Unlock()

	// 加入匹配队列
	result, err := matchService.AddMatcher(matcherCtx, matcher)
	if err != nil {
		// 如果加入失败，移除匹配中标记
		mgr.matcherLock.Lock()
		delete(mgr.activeMatchers, matcherId)
		mgr.matcherLock.Unlock()

		matcherCancel() // 发生错误时取消上下文
		return nil, ErrJoinFailed
	}

	// 创建一个有缓冲的结果通道，避免发送方阻塞
	resultCh := make(chan dto.MatchResult, 1)

	// 启动协程处理匹配结果
	mgr.wg.Add(1)
	go func() {
		defer mgr.wg.Done()
		defer matcherCancel() // 确保处理结束时取消上下文
		defer close(resultCh) // 确保正确关闭通道
		defer func() {
			// 匹配完成后，移除玩家的匹配中标记
			mgr.matcherLock.Lock()
			delete(mgr.activeMatchers, matcherId)
			mgr.matcherLock.Unlock()
		}()

		select {
		case matchResult, ok := <-result:
			if !ok {
				// 来源通道关闭
				return
			}
			// 将结果转发给调用者
			resultCh <- matchResult
		case <-matcherCtx.Done():
			// 如果是超时导致的结束，记录日志
			if errors.Is(matcherCtx.Err(), context.DeadlineExceeded) {
				log.Printf("玩家%d匹配超时\n", matcherId)
				resultCh <- dto.MatchResult{Success: false}
			}
		case <-mgr.ctx.Done():
			// 整个管理器被关闭
			log.Printf("匹配管理器关闭，玩家%d匹配取消\n", matcherId)
			resultCh <- dto.MatchResult{Success: false}
		}
	}()

	return resultCh, nil
}

// CancelMatch 取消指定玩家的匹配
func (mgr *MatchServiceMgr) CancelMatch(matchType int, matcherId int) error {
	// 检查玩家是否在匹配中
	mgr.matcherLock.RLock()
	_, exists := mgr.activeMatchers[matcherId]
	mgr.matcherLock.RUnlock()

	if !exists {
		return errors.New("玩家不在匹配队列中")
	}

	mgr.lock.RLock()
	matchService, serviceExists := mgr.services[matchType]
	mgr.lock.RUnlock()

	if !serviceExists {
		return ErrMatchTypeNotExist
	}

	// 从匹配队列中移除
	err := matchService.CancelMatch(matcherId)
	if err == nil {
		// 取消成功，移除匹配中标记
		mgr.matcherLock.Lock()
		delete(mgr.activeMatchers, matcherId)
		mgr.matcherLock.Unlock()
		log.Printf("玩家%d取消匹配成功\n", matcherId)
	}

	return err
}

// IsPlayerMatching 检查玩家是否在匹配中
func (mgr *MatchServiceMgr) IsPlayerMatching(matcherId int) bool {
	mgr.matcherLock.RLock()
	_, exists := mgr.activeMatchers[matcherId]
	mgr.matcherLock.RUnlock()
	return exists
}

// Stop 停止匹配管理器
func (mgr *MatchServiceMgr) Stop() {
	// 触发关闭信号
	mgr.cancel()

	// 等待所有处理goroutine完成
	mgr.wg.Wait()

	// 关闭所有匹配服务
	mgr.lock.Lock()
	defer mgr.lock.Unlock()

	for _, s := range mgr.services {
		_ = s.Stop() // 忽略返回的错误，确保所有服务都尝试关闭
	}

	// 清空活跃匹配者列表
	mgr.matcherLock.Lock()
	mgr.activeMatchers = make(map[int]struct{})
	mgr.matcherLock.Unlock()

	log.Println("匹配管理器已完全停止")
}
